use windows::core::Result as WinResult;
use windows::Win32::System::Com::{CLSIDFromProgID, CoCreateInstance, CLSCTX_ALL, IDispatch};
use windows::core::PCWSTR;

use crate::com::{ComObject};
use crate::variant::{variant_bool, variant_bstr, variant_i4, variant_to_string, variant_to_dispatch, variant_empty, variant_bstr_array};

pub struct CatiaApp { pub inner: ComObject }

impl CatiaApp {
    pub fn new() -> WinResult<Self> {
        let clsid = unsafe { CLSIDFromProgID(windows::core::w!("CATIA.Application"))? };
        let disp: IDispatch = unsafe { CoCreateInstance(&clsid, None, CLSCTX_ALL)? };
        Ok(Self { inner: ComObject::new(disp) })
    }

    fn to_wide_null(s: &str) -> Vec<u16> {
        s.encode_utf16().chain(std::iter::once(0)).collect()
    }

    pub fn with_progid(progid: &str) -> WinResult<Self> {
        let wide = Self::to_wide_null(progid);
        let clsid = unsafe { CLSIDFromProgID(PCWSTR(wide.as_ptr()))? };
        let disp: IDispatch = unsafe { CoCreateInstance(&clsid, None, CLSCTX_ALL)? };
        Ok(Self { inner: ComObject::new(disp) })
    }

    pub fn set_visible(&self, v: bool) -> WinResult<()> {
        self.inner.put("Visible", variant_bool(v))
    }

    pub fn version_string(&self) -> WinResult<Option<String>> {
        let v = self.inner.get("Version")?;
        let s = variant_to_string(&v)?;
        Ok(s)
    }

    pub fn documents(&self) -> WinResult<ComObject> {
        let v = self.inner.get("Documents")?;
        if let Some(disp) = variant_to_dispatch(&v)? {
            Ok(ComObject::new(disp))
        } else {
            // If missing, return an error to signal issue
            Err(windows::core::Error::from_win32())
        }
    }
}

// 统一接口抽象，便于真实与模拟实现切换
pub trait CatiaApi {
    fn set_visible(&self, v: bool) -> WinResult<()>;
    fn version_string(&self) -> WinResult<Option<String>>;
    fn documents_count(&self) -> WinResult<Option<i32>>;
    fn documents_names(&self) -> WinResult<Vec<String>>;
    fn active_document_name(&self) -> WinResult<Option<String>>;
    fn active_document_path(&self) -> WinResult<Option<String>>;
    fn windows_count(&self) -> WinResult<Option<i32>>;
    fn windows_names(&self) -> WinResult<Vec<String>>;
    fn add_document(&self, kind: &str) -> WinResult<Option<String>>;
    fn open_document(&self, path: &str) -> WinResult<Option<String>>;
    fn read_document(&self, path: &str) -> WinResult<Option<String>>;
    fn selection_count(&self) -> WinResult<Option<i32>>;
    fn selection_clear(&self) -> WinResult<()>;
    fn selection_search(&self, query: &str) -> WinResult<Option<i32>>;
    fn file_selection_box(&self, title: &str, extension: &str, mode: i32) -> WinResult<Option<String>>;
    fn save_active_document(&self) -> WinResult<bool>;
    fn save_active_document_as(&self, path: &str) -> WinResult<bool>;
    fn close_active_document(&self) -> WinResult<bool>;
    fn export_active_document(&self, path: &str, fmt: &str) -> WinResult<bool>;
    fn selection_items(&self) -> WinResult<Vec<(String, String)>>;
    fn close_all_documents(&self) -> WinResult<bool>;
    // Interactive selection (SelectElement2)
    fn selection_select_element2(&self, types: &[&str], message: &str, multi: bool) -> WinResult<Option<i32>>;
    // Enhanced selection result accessor (Type, Name, LeafProductName)
    fn selection_item_detail(&self, index_one_based: i32) -> WinResult<Option<(String, String, Option<String>)>>;
    // Batch selection details
    fn selection_details(&self) -> WinResult<Vec<(String, String, Option<String>)>>;
    // Window control
    fn windows_activate(&self, index_one_based: i32) -> WinResult<bool>;
    fn windows_activate_by_name(&self, name: &str) -> WinResult<bool>;
    // Document management
    fn save_all_documents(&self) -> WinResult<bool>;
    fn activate_document_by_name(&self, name: &str) -> WinResult<bool>;
    fn save_documents_by_names(&self, names: &[&str]) -> WinResult<bool>;
    fn close_documents_by_names(&self, names: &[&str]) -> WinResult<bool>;
}

impl CatiaApi for CatiaApp {
    fn set_visible(&self, v: bool) -> WinResult<()> { self.set_visible(v) }
    fn version_string(&self) -> WinResult<Option<String>> { self.version_string() }
    fn documents_count(&self) -> WinResult<Option<i32>> {
        use crate::variant::variant_to_i32;
        let docs = self.documents()?;
        let count_v = docs.get("Count")?;
        variant_to_i32(&count_v)
    }
    fn documents_names(&self) -> WinResult<Vec<String>> {
        use crate::variant::variant_to_i32;
        let mut names = Vec::new();
        let docs = self.documents()?;
        let count_v = docs.get("Count")?;
        let count = variant_to_i32(&count_v)?.unwrap_or(0);
        for i in 1..=count {
            let doc_v = docs.call("Item", vec![variant_i4(i)])?;
            if let Some(doc_disp) = variant_to_dispatch(&doc_v)? {
                let doc = ComObject::new(doc_disp);
                let name_v = doc.get("Name")?;
                let name = crate::variant::variant_to_string(&name_v)?.unwrap_or_default();
                names.push(name);
            }
        }
        Ok(names)
    }
    fn active_document_name(&self) -> WinResult<Option<String>> {
        let v = self.inner.get("ActiveDocument")?;
        if let Some(disp) = variant_to_dispatch(&v)? {
            let doc = ComObject::new(disp);
            let name_v = doc.get("Name")?;
            crate::variant::variant_to_string(&name_v)
        } else {
            Ok(None)
        }
    }
    fn active_document_path(&self) -> WinResult<Option<String>> {
        let v = self.inner.get("ActiveDocument")?;
        if let Some(disp) = variant_to_dispatch(&v)? {
            let doc = ComObject::new(disp);
            let path_v = doc.get("Path")?;
            crate::variant::variant_to_string(&path_v)
        } else {
            Ok(None)
        }
    }
    fn windows_count(&self) -> WinResult<Option<i32>> {
        use crate::variant::variant_to_i32;
        let v = self.inner.get("Windows")?;
        if let Some(disp) = variant_to_dispatch(&v)? {
            let wins = ComObject::new(disp);
            let count_v = wins.get("Count")?;
            variant_to_i32(&count_v)
        } else {
            Ok(Some(0))
        }
    }
    fn windows_names(&self) -> WinResult<Vec<String>> {
        use crate::variant::variant_to_i32;
        let mut names = Vec::new();
        let v = self.inner.get("Windows")?;
        if let Some(disp) = variant_to_dispatch(&v)? {
            let wins = ComObject::new(disp);
            let count_v = wins.get("Count")?;
            let count = variant_to_i32(&count_v)?.unwrap_or(0);
            for i in 1..=count {
                let w_v = wins.call("Item", vec![variant_i4(i)])?;
                if let Some(w_disp) = variant_to_dispatch(&w_v)? {
                    let w = ComObject::new(w_disp);
                    let name_v = w.get("Name")?;
                    let name = crate::variant::variant_to_string(&name_v)?.unwrap_or_default();
                    names.push(name);
                }
            }
        }
        Ok(names)
    }
    fn add_document(&self, kind: &str) -> WinResult<Option<String>> {
        let docs = self.documents()?;
        let r = docs.call("Add", vec![variant_bstr(kind)])?;
        if let Some(disp) = variant_to_dispatch(&r)? {
            let doc = ComObject::new(disp);
            let name_v = doc.get("Name")?;
            crate::variant::variant_to_string(&name_v)
        } else {
            Ok(None)
        }
    }
    fn open_document(&self, path: &str) -> WinResult<Option<String>> {
        let docs = self.documents()?;
        let r = docs.call("Open", vec![variant_bstr(path)])?;
        if let Some(disp) = variant_to_dispatch(&r)? {
            let doc = ComObject::new(disp);
            let name_v = doc.get("Name")?;
            crate::variant::variant_to_string(&name_v)
        } else {
            Ok(None)
        }
    }
    fn read_document(&self, path: &str) -> WinResult<Option<String>> {
        let docs = self.documents()?;
        let r = docs.call("Read", vec![variant_bstr(path)])?;
        if let Some(disp) = variant_to_dispatch(&r)? {
            let doc = ComObject::new(disp);
            let name_v = doc.get("Name")?;
            crate::variant::variant_to_string(&name_v)
        } else {
            Ok(None)
        }
    }
    fn selection_count(&self) -> WinResult<Option<i32>> {
        use crate::variant::variant_to_i32;
        let v = self.inner.get("ActiveDocument")?;
        if let Some(disp) = variant_to_dispatch(&v)? {
            let doc = ComObject::new(disp);
            let sel_v = doc.get("Selection")?;
            if let Some(sel_disp) = crate::variant::variant_to_dispatch(&sel_v)? {
                let sel = ComObject::new(sel_disp);
                let count_v = sel.get("Count")?;
                variant_to_i32(&count_v)
            } else {
                Ok(Some(0))
            }
        } else {
            Ok(Some(0))
        }
    }
    fn selection_clear(&self) -> WinResult<()> {
        let v = self.inner.get("ActiveDocument")?;
        if let Some(disp) = variant_to_dispatch(&v)? {
            let doc = ComObject::new(disp);
            let sel_v = doc.get("Selection")?;
            if let Some(sel_disp) = crate::variant::variant_to_dispatch(&sel_v)? {
                let sel = ComObject::new(sel_disp);
                let _ = sel.call("Clear", vec![])?;
                Ok(())
            } else {
                Ok(())
            }
        } else {
            Ok(())
        }
    }
    fn selection_search(&self, query: &str) -> WinResult<Option<i32>> {
        use crate::variant::variant_to_i32;
        let v = self.inner.get("ActiveDocument")?;
        if let Some(disp) = variant_to_dispatch(&v)? {
            let doc = ComObject::new(disp);
            let sel_v = doc.get("Selection")?;
            if let Some(sel_disp) = crate::variant::variant_to_dispatch(&sel_v)? {
                let sel = ComObject::new(sel_disp);
                let _ = sel.call("Search", vec![variant_bstr(query)])?;
                let count_v = sel.get("Count")?;
                variant_to_i32(&count_v)
            } else {
                Ok(Some(0))
            }
        } else {
            Ok(Some(0))
        }
    }
    fn file_selection_box(&self, title: &str, extension: &str, mode: i32) -> WinResult<Option<String>> {
        let r = self.inner.call("FileSelectionBox", vec![variant_bstr(title), variant_bstr(extension), variant_i4(mode)])?;
        crate::variant::variant_to_string(&r)
    }
    fn save_active_document(&self) -> WinResult<bool> {
        let v = self.inner.get("ActiveDocument")?;
        if let Some(disp) = variant_to_dispatch(&v)? {
            let doc = ComObject::new(disp);
            let _ = doc.call("Save", vec![])?;
            Ok(true)
        } else {
            Ok(false)
        }
    }
    fn save_active_document_as(&self, path: &str) -> WinResult<bool> {
        let v = self.inner.get("ActiveDocument")?;
        if let Some(disp) = variant_to_dispatch(&v)? {
            let doc = ComObject::new(disp);
            let _ = doc.call("SaveAs", vec![variant_bstr(path)])?;
            Ok(true)
        } else {
            Ok(false)
        }
    }
    fn export_active_document(&self, path: &str, fmt: &str) -> WinResult<bool> {
        let v = self.inner.get("ActiveDocument")?;
        if let Some(disp) = variant_to_dispatch(&v)? {
            let doc = ComObject::new(disp);
            let _ = doc.call("ExportData", vec![variant_bstr(path), variant_bstr(fmt)])?;
            Ok(true)
        } else {
            Ok(false)
        }
    }
    fn selection_items(&self) -> WinResult<Vec<(String, String)>> {
        use crate::variant::variant_to_i32;
        let mut items: Vec<(String, String)> = Vec::new();
        let v = self.inner.get("ActiveDocument")?;
        if let Some(disp) = variant_to_dispatch(&v)? {
            let doc = ComObject::new(disp);
            let sel_v = doc.get("Selection")?;
            if let Some(sel_disp) = crate::variant::variant_to_dispatch(&sel_v)? {
                let sel = ComObject::new(sel_disp);
                let count_v = sel.get("Count")?;
                let count = variant_to_i32(&count_v)?.unwrap_or(0);
                for i in 1..=count {
                    let elem_v = sel.call("Item2", vec![variant_i4(i)])?;
                    if let Some(elem_disp) = crate::variant::variant_to_dispatch(&elem_v)? {
                        let elem = ComObject::new(elem_disp);
                        let t_v = elem.get("Type")?;
                        let v_v = elem.get("Value")?;
                        let t = crate::variant::variant_to_string(&t_v)?.unwrap_or_default();
                        let val = crate::variant::variant_to_string(&v_v)?.unwrap_or_default();
                        items.push((t, val));
                    }
                }
            }
        }
        Ok(items)
    }
    fn close_all_documents(&self) -> WinResult<bool> {
        let docs = self.documents()?;
        // Count downwards to avoid index shifting after close
        use crate::variant::variant_to_i32;
        let count_v = docs.get("Count")?;
        let mut count = variant_to_i32(&count_v)?.unwrap_or(0);
        while count > 0 {
            let doc_v = docs.call("Item", vec![variant_i4(count)])?;
            if let Some(doc_disp) = variant_to_dispatch(&doc_v)? {
                let doc = ComObject::new(doc_disp);
                let _ = doc.call("Close", vec![])?;
            }
            count -= 1;
        }
        Ok(true)
    }
    fn close_active_document(&self) -> WinResult<bool> {
        let v = self.inner.get("ActiveDocument")?;
        if let Some(disp) = variant_to_dispatch(&v)? {
            let doc = ComObject::new(disp);
            let _ = doc.call("Close", vec![])?;
            Ok(true)
        } else {
            Ok(false)
        }
    }
    fn selection_select_element2(&self, types: &[&str], message: &str, multi: bool) -> WinResult<Option<i32>> {
        use crate::variant::variant_to_i32;
        let v = self.inner.get("ActiveDocument")?;
        if let Some(disp) = variant_to_dispatch(&v)? {
            let doc = ComObject::new(disp);
            let sel_v = doc.get("Selection")?;
            if let Some(sel_disp) = crate::variant::variant_to_dispatch(&sel_v)? {
                let sel = ComObject::new(sel_disp);
                // 传入类型 SAFEARRAY(BSTR[])
                let types_var = if types.is_empty() { variant_empty() } else { variant_bstr_array(types) };
                let _ = sel.call("SelectElement2", vec![types_var, variant_bstr(message), variant_bool(multi)])?;
                let count_v = sel.get("Count")?;
                return variant_to_i32(&count_v);
            }
        }
        Ok(None)
    }
    fn selection_item_detail(&self, index_one_based: i32) -> WinResult<Option<(String, String, Option<String>)>> {
        let v = self.inner.get("ActiveDocument")?;
        if let Some(disp) = variant_to_dispatch(&v)? {
            let doc = ComObject::new(disp);
            let sel_v = doc.get("Selection")?;
            if let Some(sel_disp) = crate::variant::variant_to_dispatch(&sel_v)? {
                let sel = ComObject::new(sel_disp);
                let elem_v = sel.call("Item2", vec![variant_i4(index_one_based)])?;
                if let Some(elem_disp) = crate::variant::variant_to_dispatch(&elem_v)? {
                    let elem = ComObject::new(elem_disp);
                    let t = crate::variant::variant_to_string(&elem.get("Type")?)?.unwrap_or_default();
                    let mut name = String::new();
                    if let Some(val_disp) = crate::variant::variant_to_dispatch(&elem.get("Value")?)? {
                        let val = ComObject::new(val_disp);
                        if let Some(n) = crate::variant::variant_to_string(&val.get("Name")?)? { name = n; }
                    }
                    let mut leaf: Option<String> = None;
                    if let Ok(lp_var) = elem.get("LeafProduct") {
                        if let Some(lp_disp) = crate::variant::variant_to_dispatch(&lp_var)? {
                            let lp = ComObject::new(lp_disp);
                            leaf = crate::variant::variant_to_string(&lp.get("Name")?)?;
                        }
                    }
                    return Ok(Some((t, name, leaf)));
                }
            }
        }
        Ok(None)
    }
    fn selection_details(&self) -> WinResult<Vec<(String, String, Option<String>)>> {
        let mut out: Vec<(String, String, Option<String>)> = Vec::new();
        if let Some(count) = self.selection_count()? { 
            for i in 1..=count { 
                if let Some(d) = self.selection_item_detail(i)? { out.push(d); }
            }
        }
        Ok(out)
    }
    fn windows_activate(&self, index_one_based: i32) -> WinResult<bool> {
        let v = self.inner.get("Windows")?;
        if let Some(disp) = variant_to_dispatch(&v)? {
            let wins = ComObject::new(disp);
            let w_v = wins.call("Item", vec![variant_i4(index_one_based)])?;
            if let Some(w_disp) = crate::variant::variant_to_dispatch(&w_v)? {
                let w = ComObject::new(w_disp);
                let _ = w.call("Activate", vec![])?;
                return Ok(true);
            }
        }
        Ok(false)
    }
    fn windows_activate_by_name(&self, name: &str) -> WinResult<bool> {
        // 优先用枚举名称匹配找到索引，再调用 Activate
        let names = self.windows_names()?;
        if let Some((idx, _)) = names.iter().enumerate().find(|(_, n)| n == &name) {
            return self.windows_activate((idx + 1) as i32);
        }
        Ok(false)
    }
    fn save_all_documents(&self) -> WinResult<bool> {
        use crate::variant::variant_to_i32;
        let docs = self.documents()?;
        let count_v = docs.get("Count")?;
        let count = variant_to_i32(&count_v)?.unwrap_or(0);
        for i in 1..=count {
            let doc_v = docs.call("Item", vec![variant_i4(i)])?;
            if let Some(doc_disp) = variant_to_dispatch(&doc_v)? {
                let doc = ComObject::new(doc_disp);
                let _ = doc.call("Save", vec![])?;
            }
        }
        Ok(true)
    }
    fn activate_document_by_name(&self, name: &str) -> WinResult<bool> {
        let docs = self.documents()?;
        let doc_v = docs.call("Item", vec![variant_bstr(name)])?;
        if let Some(doc_disp) = variant_to_dispatch(&doc_v)? {
            let doc = ComObject::new(doc_disp);
            let _ = doc.call("Activate", vec![])?;
            return Ok(true);
        }
        Ok(false)
    }
    fn save_documents_by_names(&self, names: &[&str]) -> WinResult<bool> {
        let docs = self.documents()?;
        for n in names {
            let doc_v = docs.call("Item", vec![variant_bstr(n)])?;
            if let Some(doc_disp) = variant_to_dispatch(&doc_v)? {
                let doc = ComObject::new(doc_disp);
                let _ = doc.call("Save", vec![])?;
            }
        }
        Ok(true)
    }
    fn close_documents_by_names(&self, names: &[&str]) -> WinResult<bool> {
        let docs = self.documents()?;
        for n in names {
            let doc_v = docs.call("Item", vec![variant_bstr(n)])?;
            if let Some(doc_disp) = variant_to_dispatch(&doc_v)? {
                let doc = ComObject::new(doc_disp);
                let _ = doc.call("Close", vec![])?;
            }
        }
        Ok(true)
    }
}

pub struct CatiaMock;
impl CatiaMock {
    pub fn new() -> Self { Self }
}

impl CatiaApi for CatiaMock {
    fn set_visible(&self, _v: bool) -> WinResult<()> { println!("[MOCK] Set Visible: {}", _v); Ok(()) }
    fn version_string(&self) -> WinResult<Option<String>> { Ok(Some("V5R2020 (mock)".to_string())) }
    fn documents_count(&self) -> WinResult<Option<i32>> { Ok(Some(3)) }
    fn documents_names(&self) -> WinResult<Vec<String>> {
        Ok(vec![
            "MockPart.CATPart".to_string(),
            "MockProduct.CATProduct".to_string(),
            "MockDrawing.CATDrawing".to_string(),
        ])
    }
    fn active_document_name(&self) -> WinResult<Option<String>> { Ok(Some("MockDocument.CATPart".to_string())) }
    fn active_document_path(&self) -> WinResult<Option<String>> { Ok(Some("C\\\\Mock\\\\MockDocument.CATPart".to_string())) }
    fn add_document(&self, kind: &str) -> WinResult<Option<String>> {
        println!("[MOCK] Add Document: {}", kind);
        let name = match kind {
            "Part" => "Part1.CATPart",
            "Product" => "Product1.CATProduct",
            "Drawing" => "Drawing1.CATDrawing",
            _ => "Unknown1.CATDoc",
        };
        Ok(Some(name.to_string()))
    }
    fn open_document(&self, path: &str) -> WinResult<Option<String>> {
        println!("[MOCK] Open Document: {}", path);
        let name = std::path::Path::new(path)
            .file_name()
            .and_then(|s| s.to_str())
            .unwrap_or("OpenedDoc.CATDoc")
            .to_string();
        Ok(Some(name))
    }
    fn read_document(&self, path: &str) -> WinResult<Option<String>> {
        println!("[MOCK] Read Document: {}", path);
        let name = std::path::Path::new(path)
            .file_name()
            .and_then(|s| s.to_str())
            .unwrap_or("ReadDoc.CATDoc")
            .to_string();
        Ok(Some(name))
    }
    fn selection_count(&self) -> WinResult<Option<i32>> { Ok(Some(2)) }
    fn selection_clear(&self) -> WinResult<()> { println!("[MOCK] Selection.Clear()"); Ok(()) }
    fn selection_search(&self, query: &str) -> WinResult<Option<i32>> {
        println!("[MOCK] Selection.Search(\"{}\")", query);
        let count = if query.to_lowercase().contains("line") { 3 } else { 1 };
        Ok(Some(count))
    }
    fn file_selection_box(&self, title: &str, extension: &str, mode: i32) -> WinResult<Option<String>> {
        println!("[MOCK] FileSelectionBox(title='{}', ext='{}', mode={})", title, extension, mode);
        Ok(Some(format!("C\\\\Mock\\\\selected.{}", extension)))
    }
    fn save_active_document(&self) -> WinResult<bool> {
        println!("[MOCK] ActiveDocument.Save()");
        Ok(true)
    }
    fn save_active_document_as(&self, path: &str) -> WinResult<bool> {
        println!("[MOCK] Save ActiveDocument As: {}", path);
        Ok(true)
    }
    fn close_active_document(&self) -> WinResult<bool> {
        println!("[MOCK] Close ActiveDocument");
        Ok(true)
    }
    fn export_active_document(&self, path: &str, fmt: &str) -> WinResult<bool> {
        println!("[MOCK] ActiveDocument.ExportData(path='{}', fmt='{}')", path, fmt);
        Ok(true)
    }
    fn selection_items(&self) -> WinResult<Vec<(String, String)>> {
        println!("[MOCK] Selection.Items()");
        Ok(vec![
            ("Point".to_string(), "Point.1".to_string()),
            ("Line".to_string(), "Line.1".to_string()),
        ])
    }
    fn windows_count(&self) -> WinResult<Option<i32>> { Ok(Some(2)) }
    fn windows_names(&self) -> WinResult<Vec<String>> { Ok(vec!["Window1".into(), "Window2".into()]) }
    fn close_all_documents(&self) -> WinResult<bool> { println!("[MOCK] Close all documents"); Ok(true) }
    fn selection_select_element2(&self, types: &[&str], message: &str, multi: bool) -> WinResult<Option<i32>> {
        println!("[MOCK] Selection.SelectElement2(types={:?}, message='{}', multi={})", types, message, multi);
        let base = 1i32;
        let cnt = if multi { base + (types.len() as i32 - 1).max(0) } else { base };
        Ok(Some(cnt))
    }
    fn selection_item_detail(&self, index_one_based: i32) -> WinResult<Option<(String, String, Option<String>)>> {
        let data = vec![
            ("Face".to_string(), "Pad.1".to_string(), Some("Part1".to_string())),
            ("Edge".to_string(), "Sketch.2".to_string(), Some("Part1".to_string())),
            ("Vertex".to_string(), "Point.3".to_string(), None),
        ];
        Ok(data.get((index_one_based-1) as usize).cloned())
    }
    fn selection_details(&self) -> WinResult<Vec<(String, String, Option<String>)>> {
        let mut out = Vec::new();
        if let Some(count) = self.selection_count()? {
            for i in 1..=count {
                if let Some(d) = self.selection_item_detail(i)? { out.push(d); }
            }
        }
        Ok(out)
    }
    fn windows_activate(&self, index_one_based: i32) -> WinResult<bool> {
        println!("[MOCK] Windows.Item({}).Activate()", index_one_based);
        Ok(true)
    }
    fn windows_activate_by_name(&self, name: &str) -> WinResult<bool> {
        println!("[MOCK] Activate window by name: '{}'", name);
        // 简单模拟：若名称存在于列表则返回 true
        let exists = self.windows_names()?.iter().any(|n| n == name);
        Ok(exists)
    }
    fn save_all_documents(&self) -> WinResult<bool> {
        println!("[MOCK] Save all documents");
        Ok(true)
    }
    fn activate_document_by_name(&self, name: &str) -> WinResult<bool> {
        println!("[MOCK] Activate document by name: '{}'", name);
        let exists = self.documents_names()?.iter().any(|n| n == name);
        Ok(exists)
    }
    fn save_documents_by_names(&self, names: &[&str]) -> WinResult<bool> {
        println!("[MOCK] Save documents by names: {:?}", names);
        Ok(true)
    }
    fn close_documents_by_names(&self, names: &[&str]) -> WinResult<bool> {
        println!("[MOCK] Close documents by names: {:?}", names);
        Ok(true)
    }
}